package com.zhw.mybatis.config;

import com.zhw.mybatis.mapping.MappedStatement;

import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLDecoder;
import java.util.*;

//是全局变量 必须要设置成单例形式
public class ZhwConfiguration {

    private String scanPath;

    private DataSource dataSource;

    public static HashMap<String, MappedStatement> mappedStatements = new HashMap<String, MappedStatement>();

    //维护的自定义mapper接口 解析的sql,namespace,id
    protected final List<Class> mappers = new ArrayList();

    //私有化构造函数
    private ZhwConfiguration(){
    }

    //枚举单例设计模式
    public enum SingleZhwConfiguration{
        INSTENCE;
        private ZhwConfiguration configuration;
        SingleZhwConfiguration(){
            configuration = new ZhwConfiguration();
        }
        public ZhwConfiguration getInstence(){
            return configuration;
        }
    }

    //set() get()
    public List<Class> getMappers() {
        return mappers;
    }

    //传入的是接口
    public void addMappers(Class clazz) {
        mappers.add(clazz);
    }


    public MappedStatement getMappedStatement(String id){
        return mappedStatements.get(id);
    }

    public String getScanPath() {
        return scanPath;
    }

    public void setScanPath(String scanPath) {
        this.scanPath = scanPath;
    }

    public DataSource getDataSource() {
        return dataSource;
    }

    public void setDataSource(DataSource dataSource) {
        this.dataSource = dataSource;
    }



    //build 统一处理逻辑
    public void build() {
        //添加时候进行sql文件解析
        if(null == this.scanPath || this.scanPath.equals("")){
            this.scanPath = this.getClass().getPackage().toString();
            //判断Mapper接口和Mapperxml接口文件是否一致
            //去找mapper接口下的 xml文件，如果不存在则报错
            
        }else{
            List<Class<?>> aClasss = getClass(this.scanPath);
            for (Class<?> claz : aClasss) {
                regiestMapper(claz);
            }
        }
    }

    /**
     * 注册mapperxml文件 模拟xml解析过程
     * @param clazz
     */
    public void regiestMapper(Class clazz){
        try {
            Method mappedStatementMethod = clazz.getSuperclass().getDeclaredMethod("getMappedStatement",null);
            HashMap<String, MappedStatement> statementHashMap = (HashMap<String, MappedStatement>)mappedStatementMethod.invoke(clazz.newInstance(), null);
            mappedStatements.putAll(statementHashMap);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


    /**
     * 根据包名获取包下所有类
     */
    public static  List<Class<?>> getClass(String scanPath){
        // 是否循环搜索子包
        boolean recursive = true;
        List<Class<?>> clazzs = new ArrayList<Class<?>>();
        try {
            String classPathToFilePath = scanPath.replace(".","/");
            Enumeration<URL> resources = Thread.currentThread().getContextClassLoader().getResources(classPathToFilePath);
            while(resources.hasMoreElements()){
                URL url = resources.nextElement();
                String protocol = url.getProtocol();
                if ("file".equals(protocol)) {
                    String filePath = URLDecoder.decode(url.getFile(), "UTF-8");
                    findClassInPackageByFile(scanPath, filePath, recursive, clazzs);
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return clazzs;
    }

    /**
     * 在package对应的路径下找到所有的class
     */
    public static void findClassInPackageByFile(String packageName, String filePath, final boolean recursive,
                                                List<Class<?>> clazzs) {
        File dir = new File(filePath);
        if (!dir.exists() || !dir.isDirectory()) {
            return;
        }
        // 在给定的目录下找到所有的文件，并且进行条件过滤
        File[] dirFiles = dir.listFiles(new FileFilter() {
            public boolean accept(File file) {
                boolean acceptDir = recursive && file.isDirectory();// 接受dir目录
                boolean acceptClass = file.getName().endsWith("class");// 接受class文件
                return acceptDir || acceptClass;
            }
        });

        for (File file : dirFiles) {
            if (file.isDirectory()) {
                findClassInPackageByFile(packageName + "." + file.getName(), file.getAbsolutePath(), recursive, clazzs);
            } else {
                String className = file.getName().substring(0, file.getName().length() - 6);
                try {
                    Class<?> aClass = Thread.currentThread().getContextClassLoader().loadClass(packageName + "." + className);
                    clazzs.add(aClass);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }
}
